Boxplot = Class.create(Configurable, {
    arr_data_ : new Array,
    initialize: function(options) 
    {
        this.setOptions(options);
        this.readData();
        this.createBoxplot();
    },
    readData : function()
    {
        $$(this.options.data_selector).each(function(element){
            this.arr_data_.push(parseInt(element.innerHTML));
        }.bind(this));
    },
    createBoxplot : function()
    {
        var max, min, median, box_lower_border, box_upper_border, box_lower_outlier, box_upper_outlier, top_value, bottom_value, has_lower_outlier, has_upper_outlier, range, cpp, height, plot_height, plot_width, bottom_whisker_y, top_whisker_y;
        height = $(this.options.boxplot_holder_id).getHeight();
        plot_height = height-2*this.options.boxplot_margin;
        plot_width = this.options.boxplot_width-this.options.boxplot_margin*2;
        raphael = Raphael(this.options.boxplot_holder_id, this.options.boxplot_width, height);
        range = parseFloat($('plot_range').innerHTML);
        //cases per pixel
        cpp = range / plot_height;
        max = parseFloat($('plot_max').innerHTML);
        min = parseFloat($('plot_min').innerHTML);
        median = parseFloat($('plot_median').innerHTML);
        box_lower_border = parseFloat($('plot_box_lower_border').innerHTML);
        box_upper_border = parseFloat($('plot_box_upper_border').innerHTML);
        box_lower_outlier = parseFloat($('plot_box_lower_outlier').innerHTML);
        box_upper_outlier = parseFloat($('plot_box_upper_outlier').innerHTML);
        top_value = parseFloat($('plot_top_value').innerHTML);
        bottom_value = parseFloat($('plot_bottom_value').innerHTML);
        bottom_whisker_y = bottom_value == box_lower_outlier ? Math.round(range/cpp) : Math.round((range-Math.abs(bottom_value-box_lower_outlier))/cpp);
        top_whisker_y = top_value == box_upper_outlier ? this.options.boxplot_margin : Math.round(Math.abs(top_value-box_upper_outlier)/cpp);
        bottom_whisker_y += this.options.boxplot_margin;
        top_whisker_y += this.options.boxplot_margin;
        var box = raphael.rect(this.options.boxplot_margin, Math.round((top_value-box_upper_border)/cpp)+this.options.boxplot_margin, plot_width, Math.round((box_upper_border-box_lower_border)/cpp));
        box.attr({fill: "yellow", opacity: 0.9});
        var median = raphael.path("M"+this.options.boxplot_margin+" "+(Math.round((top_value-median)/cpp)+this.options.boxplot_margin)+"L"+(this.options.boxplot_width-this.options.boxplot_margin)+" "+ (Math.round((top_value-median)/cpp)+this.options.boxplot_margin));
        median.attr({stroke: "red", "stroke-width": 3});
        var lower_whisker1 = raphael.path("M"+Math.round(this.options.boxplot_width/2)+" "+(Math.round((top_value-box_lower_border)/cpp)+this.options.boxplot_margin)+"L"+Math.round(this.options.boxplot_width/2)+" "+ bottom_whisker_y);
        var lower_whisker2 = raphael.path("M"+this.options.boxplot_margin+" "+bottom_whisker_y+"L"+(this.options.boxplot_width-this.options.boxplot_margin)+" "+ bottom_whisker_y);
        var upper_whisker1 = raphael.path("M"+Math.round(this.options.boxplot_width/2)+" "+(Math.round((top_value-box_upper_border)/cpp)+this.options.boxplot_margin)+"L"+Math.round(this.options.boxplot_width/2)+" "+ top_whisker_y);
        var upper_whisker2 = raphael.path("M"+this.options.boxplot_margin+" "+ top_whisker_y+"L"+(this.options.boxplot_width-this.options.boxplot_margin)+" "+ top_whisker_y);
        for(cnt=0; cnt < this.arr_data_.length; ++cnt)
        {
            var c = raphael.circle(Math.round(this.options.boxplot_width/2), Math.round(Math.abs(top_value-this.arr_data_[cnt])/cpp)+this.options.boxplot_margin, 5);
            c.attr({fill: "yellow", opacity: 0.6, "href" : "#"+this.options.label_id+cnt});
            c.hover(function() {
                //this.flag = raphael.g.popup(this.getBBox().x+Math.floor(this.getBBox().width/2), this.getBBox().y, (this.attr('title') || "0") + " ").insertBefore(this);
                //this.flag.toFront();
                this.animate({"scale": "2,2"}, 250);
                $(this.attr('href').gsub("#","")).show();
            }, function() {
                //this.flag.animate({opacity: 0}, 100, function () {this.remove();});
                this.animate({"scale": "1,1"}, 250);
                $(this.attr('href').gsub("#","")).hide();
            });
        }
    }
});

Boxplot.DEFAULT_OPTIONS = {
    boxplot_holder_id: 'boxplot',
    data_selector: 'ul.boxplot-values li li',
    boxplot_width: 200,
    boxplot_margin: 40,
    label_id: 'plot_value_'
};
new Boxplot();
